<?php


namespace app\common\command;

use app\common\enum\CrontabEnum;
use app\common\model\crontab\SysCrontab;
use Exception;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use tmcore\services\CronExpressionService;

/**
 * 计划任务
 */
class Crontab extends Command
{
    /**
     * 指令配置
     */
    protected function configure()
    {
        $this->setName('crontab')
            ->setDescription('定时任务');
    }

    /**
     * 执行任务(分钟级)
     * @param Input $input
     * @param Output $output
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected function execute(Input $input, Output $output): bool
    {
        $list = SysCrontab::where(['status' => CrontabEnum::START])->select()->toArray();
        if (empty($list)) return false;

        $cronExpressionService = (new CronExpressionService);

        foreach ($list as $cron) {
            $nextTime = $cronExpressionService->getTimestamp($cron['expression'], $cron['last_time']);
            if ($nextTime >= time()) continue; // 未到执行时间

            $startTime = microtime(true);
            try {
                $params = empty($cron['params'])?[]:explode(' ', $cron['params']);
                $cronExpressionService->cronCall($cron['command'], $params);
                SysCrontab::edit(['error'=>''], $cron['id']);
            } catch (Exception $e) {
                SysCrontab::edit(['error'=>$e->getMessage(), 'status'=> CrontabEnum::ERROR], $cron['id']);
            } finally {
                $endTime = microtime(true) - $startTime;
                $maxTime = $cron['max_time'] > $endTime ? $cron['max_time'] : $endTime;
                SysCrontab::edit(['last_time'=>time(), 'exe_time'=>$endTime, 'max_time'=>$maxTime], $cron['id']);
            }
        }

        return true;
    }
}